package com.kexio.config.manager;

import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.kexio.common.cache.RedisUtil;
import com.kexio.config.entity.SystemConfig;

import cn.hutool.core.util.StrUtil;

/**
 * 配置管理器
 * 负责配置的缓存管理和读写操作
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Component
public class ConfigManager {
    
    private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
    
    private static final String CONFIG_CACHE_PREFIX = "config:";
    private static final String CONFIG_VERSION_KEY = "config:version";
    
    @Autowired(required = false)
    private RedisUtil redisUtil;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 本地缓存 (L1)
    private final Cache<String, String> localCache = Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(Duration.ofMinutes(10))
        .build();
    
    // 配置变更监听器
    private final ConcurrentHashMap<String, ConfigChangeListener> listeners = new ConcurrentHashMap<>();
    
    /**
     * 获取配置值
     */
    public String getConfigValue(String key) {
        if (StrUtil.isBlank(key)) {
            return null;
        }
        
        try {
            // 先从本地缓存获取
            String value = localCache.getIfPresent(key);
            if (value != null) {
                logger.debug("从本地缓存获取配置: key={}, value={}", key, maskValue(value));
                return value;
            }
            
            // 从Redis获取
            if (redisUtil != null) {
                value = redisUtil.get(CONFIG_CACHE_PREFIX + key);
                if (value != null) {
                    localCache.put(key, value);
                    logger.debug("从Redis缓存获取配置: key={}, value={}", key, maskValue(value));
                    return value;
                }
            }
            
            // 从数据库获取 (这里模拟)
            value = getConfigFromDatabase(key);
            if (value != null) {
                // 写入缓存
                localCache.put(key, value);
                if (redisUtil != null) {
                    redisUtil.set(CONFIG_CACHE_PREFIX + key, value, Duration.ofHours(1));
                }
                logger.debug("从数据库获取配置: key={}, value={}", key, maskValue(value));
                return value;
            }
            
        } catch (Exception e) {
            logger.error("获取配置失败: key={}", key, e);
        }
        
        return null;
    }
    
    /**
     * 设置配置值
     */
    public boolean setConfigValue(String key, String value) {
        if (StrUtil.isBlank(key)) {
            return false;
        }
        
        try {
            String oldValue = getConfigValue(key);
            
            // 保存到数据库 (这里模拟)
            boolean result = saveConfigToDatabase(key, value);
            
            if (result) {
                // 更新缓存
                localCache.put(key, value);
                if (redisUtil != null) {
                    redisUtil.set(CONFIG_CACHE_PREFIX + key, value, Duration.ofHours(1));
                }
                
                // 通知配置变更
                notifyConfigChange(key, oldValue, value);
                
                logger.info("配置更新成功: key={}, oldValue={}, newValue={}", 
                           key, maskValue(oldValue), maskValue(value));
                return true;
            }
            
        } catch (Exception e) {
            logger.error("设置配置失败: key={}, value={}", key, maskValue(value), e);
        }
        
        return false;
    }
    
    /**
     * 删除配置
     */
    public boolean deleteConfig(String key) {
        if (StrUtil.isBlank(key)) {
            return false;
        }
        
        try {
            String oldValue = getConfigValue(key);
            
            // 从数据库删除 (这里模拟)
            boolean result = deleteConfigFromDatabase(key);
            
            if (result) {
                // 清除缓存
                localCache.invalidate(key);
                if (redisUtil != null) {
                    redisUtil.delete(CONFIG_CACHE_PREFIX + key);
                }
                
                // 通知配置变更
                notifyConfigChange(key, oldValue, null);
                
                logger.info("配置删除成功: key={}, oldValue={}", key, maskValue(oldValue));
                return true;
            }
            
        } catch (Exception e) {
            logger.error("删除配置失败: key={}", key, e);
        }
        
        return false;
    }
    
    /**
     * 清空缓存
     */
    public void clearCache() {
        try {
            localCache.invalidateAll();
            if (redisUtil != null) {
                redisUtil.deleteByPattern(CONFIG_CACHE_PREFIX + "*");
            }
            logger.info("配置缓存清空成功");
        } catch (Exception e) {
            logger.error("清空配置缓存失败", e);
        }
    }
    
    /**
     * 清空指定配置的缓存
     */
    public void clearCache(String key) {
        try {
            localCache.invalidate(key);
            if (redisUtil != null) {
                redisUtil.delete(CONFIG_CACHE_PREFIX + key);
            }
            logger.info("配置缓存清除成功: key={}", key);
        } catch (Exception e) {
            logger.error("清除配置缓存失败: key={}", key, e);
        }
    }
    
    /**
     * 注册配置变更监听器
     */
    public void addConfigChangeListener(String key, ConfigChangeListener listener) {
        listeners.put(key, listener);
        logger.debug("注册配置变更监听器: key={}", key);
    }
    
    /**
     * 移除配置变更监听器
     */
    public void removeConfigChangeListener(String key) {
        listeners.remove(key);
        logger.debug("移除配置变更监听器: key={}", key);
    }
    
    /**
     * 从数据库获取配置 (模拟实现)
     */
    private String getConfigFromDatabase(String key) {
        // 这里应该注入Mapper进行数据库查询
        logger.debug("从数据库查询配置: key={}", key);
        
        // 模拟一些默认配置
        switch (key) {
            case "system.title":
                return "Kexio管理系统";
            case "system.version":
                return "1.0.0";
            case "system.author":
                return "Kexio Team";
            case "cache.expire.minutes":
                return "60";
            case "upload.max.size":
                return "10485760"; // 10MB
            default:
                return null;
        }
    }
    
    /**
     * 保存配置到数据库 (模拟实现)
     */
    private boolean saveConfigToDatabase(String key, String value) {
        // 这里应该注入Mapper进行数据库保存
        logger.debug("保存配置到数据库: key={}, value={}", key, maskValue(value));
        
        // 模拟保存成功
        return Math.random() > 0.1; // 90%成功率
    }
    
    /**
     * 从数据库删除配置 (模拟实现)
     */
    private boolean deleteConfigFromDatabase(String key) {
        // 这里应该注入Mapper进行数据库删除
        logger.debug("从数据库删除配置: key={}", key);
        
        // 模拟删除成功
        return Math.random() > 0.1; // 90%成功率
    }
    
    /**
     * 通知配置变更
     */
    private void notifyConfigChange(String key, String oldValue, String newValue) {
        try {
            ConfigChangeListener listener = listeners.get(key);
            if (listener != null) {
                listener.onConfigChange(key, oldValue, newValue);
            }
            
            // 全局监听器
            ConfigChangeListener globalListener = listeners.get("*");
            if (globalListener != null) {
                globalListener.onConfigChange(key, oldValue, newValue);
            }
            
        } catch (Exception e) {
            logger.error("通知配置变更失败: key={}", key, e);
        }
    }
    
    /**
     * 掩码敏感值
     */
    private String maskValue(String value) {
        if (value == null || value.length() <= 4) {
            return "***";
        }
        return value.substring(0, 2) + "***" + value.substring(value.length() - 2);
    }
    
    /**
     * 配置变更监听器接口
     */
    public interface ConfigChangeListener {
        void onConfigChange(String key, String oldValue, String newValue);
    }
}
